package com.file.parser;


import com.file.bo.ResponseData;
import com.file.bo.mail.JsBank;
import com.file.bo.mail.JsBankTran;
import com.file.constant.ErrorCode;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import technology.tabula.*;
import technology.tabula.detectors.NurminenDetectionAlgorithm;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.File;
import java.util.*;

/**
 * 丰巢-南京银行的pdf解析类
 * @author v_wbstlu
 * @date 2023-09-25
 */
@Slf4j
public class JsBankPdfParser extends BasePdfParser{

	public ResponseData<String> parseJSPdfToJson(String daId, String filePath) {
		log.info("parseJSPdfToJson started, daId:{}", daId);
		String json = null;

		try {
			JsBank jsBank = parseJSPdf(filePath);
			json = JsonUtils.convertObjectToJson(jsBank);
			doAlert(daId, jsBank);
		} catch (Exception e) {
			log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseJSPdfToJson failed", e);
			return new ResponseData<String>(json, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
		}

    	log.info("parseJSPdfToJson completed, daId:{}", daId);
		return new ResponseData<String>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
	}

	public JsBank parseJSPdf(String filePath) {
		List<JsBankTran> jsBankTrans = parseTrans(filePath);

		JsBank jsBank = parseJSHeader(filePath);

		jsBank.setJsBankTrans(jsBankTrans);

		return jsBank;
	}

	public JsBank parseJSHeader(String filePath) {
		JsBank jsBank = new JsBank();
		String pdfHeaderText = parsePdfHeaderText(filePath);

		String cardNo = pdfHeaderText.substring(pdfHeaderText.indexOf("江苏银行交易明细卡号/账号：") + 14, pdfHeaderText.indexOf("客户名称：")).replaceAll(" ", "");//NOSONAR
		String name = pdfHeaderText.substring(pdfHeaderText.indexOf("客户名称：") + 5,pdfHeaderText.indexOf("起始日期：")).replaceAll(" ", "");//NOSONAR
		String startDate = pdfHeaderText.substring(pdfHeaderText.indexOf("起始日期：") + 5,pdfHeaderText.indexOf("结束日期：")).replaceAll(" ", "");//NOSONAR
		String endDate = pdfHeaderText.substring(pdfHeaderText.indexOf("结束日期：") + 5,pdfHeaderText.indexOf("序号 摘要/附言")).replaceAll(" ", "");//NOSONAR
		String applyDateTime = pdfHeaderText.substring(pdfHeaderText.indexOf("申请时间：") + 5,pdfHeaderText.indexOf("页码")).trim();
		jsBank.setCardNo(cardNo);
		jsBank.setName(name);
		jsBank.setStartDate(startDate);
		jsBank.setEndDate(endDate);
		jsBank.setApplyDateTime(applyDateTime);
		return jsBank;
	}

	public List<JsBankTran> parseTrans(String filePath) {
		List<JsBankTran> jsBankTrans = new ArrayList<>();

		// 1. 读取文件
		File pdf = new File(filePath);

		// 2. pdfbox读取PDDocument
		try (PDDocument pdfDocument = PDDocument.load(pdf)) {

			// 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
			ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
			NurminenDetectionAlgorithm detectionAlgorithm = new NurminenDetectionAlgorithm();
			Map<Integer, List<Rectangle>> detectedTables = new HashMap<>();

			// 4. 获取每页的PageIterator
			PageIterator pages = objectExtractor.extract();

			// 5. 解析每页的Rectangle(table的位置)
			while (pages.hasNext()) {
				Page page = pages.next();
				List<Rectangle> tablesOnPage = detectionAlgorithm.detect(page);
				if (tablesOnPage.size() > 0) {
					detectedTables.put(Integer.valueOf(page.getPageNumber()), tablesOnPage);
				}
			}

			// 6.通过table位置获取表格具体内容
			SpreadsheetExtractionAlgorithm bea = new SpreadsheetExtractionAlgorithm();

			// 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
			for (Map.Entry<Integer, List<Rectangle>> entry : detectedTables.entrySet()) {
				Page page = objectExtractor.extract(entry.getKey());

				// 江苏银行默认每页只有一个表格，因此获取第0个rectangle
				Rectangle rectangle = entry.getValue().get(0);
				Page area = page.getArea(rectangle.getTop(), rectangle.getLeft(),rectangle.getBottom(),rectangle.getRight());

				List<Table> table = bea.extract(area);

				// 江苏银行默认每页只有一个表格，因此获取第0个table
				Table t = table.get(0);

				if (t.getColCount() != 9 && t.getColCount() != 7) {
					log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), "", "", "", "JsBank Pdf format changed");
					throw new RuntimeException();
				}

				for (int i = 0; i < t.getRowCount(); i++) {

					if (t.getCell(i,0).getText(false).contains("序号")) {
						continue;
					}
					JsBankTran jsBankTran = getTransactionByTable(t, i);
					if (StringUtils.isNotBlank(jsBankTran.getId())) {
						jsBankTrans.add(jsBankTran);
					}
				}

			}
		}  catch (Exception e) {
			throw new RuntimeException(e);
		}

		return jsBankTrans;
	}

	private JsBankTran getTransactionByTable(Table t, int i) {
		JsBankTran aliPayTran = new JsBankTran();
		aliPayTran.setId(t.getCell(i,0).getText(false));
		aliPayTran.setSummary(t.getCell(i,1).getText(false));
		aliPayTran.setCurrency(t.getCell(i,2).getText(false));
		aliPayTran.setDate(t.getCell(i,3).getText(false));
		aliPayTran.setTranType(t.getCell(i,4).getText(false));
		aliPayTran.setTranAmt(t.getCell(i,5).getText(false));
		aliPayTran.setBalance(t.getCell(i,6).getText(false));
		if (Objects.nonNull(t.getCell(i,7))) {
			aliPayTran.setCounterPartyAccountNumber(t.getCell(i,7).getText(false));
		}
		if (Objects.nonNull(t.getCell(i,8))) {
			aliPayTran.setCounterPartyAccountName(t.getCell(i,8).getText(false));
		}

		return aliPayTran;
	}

	private void doAlert(String daId, JsBank jsBank) {
		log.info("doAlert started daId: {}", daId);
		//加入字段告警
		if (StringUtils.isBlank(jsBank.getCardNo())) {
			log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseJSPdfToJson JsBank cardNo is null");
			throw new RuntimeException();
		}
		if (StringUtils.isBlank(jsBank.getName())) {
			log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseJSPdfToJson JsBank Name is null");
			throw new RuntimeException();
		}
		if (StringUtils.isBlank(jsBank.getStartDate())) {
			log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseJSPdfToJson JsBank startDate is null");
			throw new RuntimeException();
		}
		if (StringUtils.isBlank(jsBank.getEndDate())) {
			log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseJSPdfToJson JsBank endDate is null");
			throw new RuntimeException();
		}

		List<JsBankTran> jsBankTrans = jsBank.getJsBankTrans();
		if (jsBankTrans.size() == 0) {
			log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseJSPdfToJson jsBankTrans size is 0");
		}

		for (JsBankTran jsBankTran : jsBankTrans) {
			if (StringUtils.isBlank(jsBankTran.getId())) {
				log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseJSPdfToJson jsBankTran id is null");
				throw new RuntimeException();
			}
//			if (StringUtils.isBlank(jsBankTran.getSummary())) {
//				log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseJSPdfToJson jsBankTran summary is null");
//				throw new RuntimeException();
//			}
			if (StringUtils.isBlank(jsBankTran.getDate())) {
				log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseJSPdfToJson jsBankTran date is null");
				throw new RuntimeException();
			}
			if (StringUtils.isBlank(jsBankTran.getTranType())) {
				log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseJSPdfToJson jsBankTran tranType is null");
				throw new RuntimeException();
			}
			if (StringUtils.isBlank(jsBankTran.getTranAmt())) {
				log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseJSPdfToJson jsBankTran tranAmt is null");
				throw new RuntimeException();
			}
			if (StringUtils.isBlank(jsBankTran.getBalance())) {
				log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseJSPdfToJson jsBankTran balance is null");
				throw new RuntimeException();
			}

		}
	}

	public static void main(String[] args) {
		JsBankPdfParser pdfParser = new JsBankPdfParser();

		JsBank jsBank = pdfParser.parseJSPdf("D:\\data\\file\\4-000001541524291-2.pdf");
		System.out.println(JsonUtils.convertObjectToJson(jsBank));

	}

}
